<?php
/**
 * 用swoole 搭建的一个TCP异步API服务器
 * 这是一个最简单的简易框架
 * api为接口目录，支持自定义类似模块
 * console为命令执行任务
 * task为task任务目录
 * time_task为轮询式的定时任务
 * server为tcp异步服务器也是框架的核心文件
 * 接口目前仅支持接收xxx-www-urldecoded的数据方式
 * 后续按需加入其他方式
 * 接口返回为json
 *
 * 自动加载的目录包括
 * common
 * vendor
 * api目录下的controller
 * 可以自己在Autoload文件的autoDir方法中配置对应加载目录
 */

$serv = new swoole_server('0.0.0.0', 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP);
$serv->set(array(
    'worker_num' => 2,
    'reactor_num' => 2,
    'daemonize' => false,
    'backlog' => 128,
    'task_worker_num' => 5,
    'dispatch_mode' => 3,
    'enable_coroutine' => false,
));

$serv->on('WorkerStart', 'onWorkerStart');
$serv->on('Connect', 'onConnect');
$serv->on('Receive', 'onReceive');
$serv->on('Close', 'onClose');
$serv->on('task', 'onTask'); // 同步事件，接收worker投递的任务，task_num的设置需要参照任务执行的时间及worker投递任务的时间
$serv->on('finish', 'onFinish'); // task完成时触发

$serv->start();

/**
 * 框架的初始化
 * 数据和资源在此
 * 引入，节省开销
 * 服务器不退出，这里
 * 的数据不会释放
 *
 * @param $serv
 * @param $worder_id
 */
function onWorkerStart($serv, $worder_id) {
    //路径常量定义
    define('SWL_ROOT', dirname(__DIR__));
    define('SWL_COMMON', SWL_ROOT . DIRECTORY_SEPARATOR . 'common');
    define('SWL_VENDOR', SWL_ROOT . DIRECTORY_SEPARATOR . 'vendor');
    define('SWL_TASK', SWL_ROOT . DIRECTORY_SEPARATOR . 'task');

    // 自动加载
    //require_once SWL_VENDOR . '/Autoload.php'; // 这个可以抛弃
    include_once SWL_VENDOR . '/Loader.php'; // 引入加载器
    spl_autoload_register( 'Loader::autoload', true, false); // 注册自动加载
    //spl_autoload_register('__autoload', true, false);

}

/**
 * Http建立连接回调函数
 */
function onConnect($serv, $fd)
{
    //echo "Server is running on 127.0.0.1:9888".PHP_EOL;
}

/**
 * 开始接受客户端信息回调函数
 * 业务逻辑始于这里，在这里捕捉所有的异常
 * 便于调试
 */
function onReceive($serv, $fd, $from_id, $data)
{
    try{
        // 开始处理接收的数据及路径解析和分发控制器执行action
        s_vendor\App::start($serv, $fd, $data);
    } catch(\Exception $e) {
        var_dump($e->getMessage());
    }
}

/**
 * 连接关闭后回调函数
 */
function onClose($serv, $fd)
{
    return false;
}

// 这里是一个处理task的工厂，task的业务逻辑在通过继承实现AbstractTask的execute方法实现
/*function onTask(swoole_server $serv, $task_id, $work_id, s_vendor\AbstractTask $task) {
    if ($task instanceof s_vendor\AbstractTask) {
        $res = $task->execute();
        onFinish($serv, $task_id, $res);
    } else {
        throw new Exception('投递的task任务第一个参数必须是继承AbstractTask的类');
        onFinish($serv, $task_id, $task);
    }
}*/

/**
 * @param \swoole_Server $serv
 * @param $task_id
 * @param $work_id
 * @param $task_root
 * @throws Exception
 */
function onTask(\swoole_server $serv, $task_id, $work_id, $task_root) {
    try {
        $taskM = new $task_root();
        if ($taskM  instanceof s_vendor\AbstractTask) {
            $response = $taskM->execute();
            $res = ['response' => $response, 'finish' => $taskM];
            $serv->finish($res);
        } else {
            throw new Exception('投递的task任务第一个参数必须是继承AbstractTask的类');
        }
    } catch (\Exception $e) {
        throw new Exception('投递task任务失败：' . $e->getMessage());
    }
}


function onFinish(swoole_server $serv, $task_id, $data)
{
    $finish_data = $data['response'];
    $finishM = $data['finish'];
    $finishM->finish($finish_data);
}
